package com.contory.ssn_lgnd.framework.math;

import java.util.ArrayList;
import java.util.LinkedList;

import android.util.FloatMath;
import android.util.Log;

public class Polygon {
	public LinkedList<Vector2> pointList;
	private LinkedList<Vector2> edgeList;
	private LinkedList<Vector2> orinPointList;
	private Vector2 viewPos;
	private Vector2 polyCordCenPos;
	private Rectangle boundingBox;
	private boolean lockBoolean = false;
	private Vector2 avrCenPos;
	private float polyCordW = 0;
	private float polyCordH = 0;
	
	public Polygon(){
		pointList = new LinkedList<Vector2>();
		edgeList = new LinkedList<Vector2>();
		orinPointList = new LinkedList<Vector2>();
		viewPos = new Vector2();
		polyCordCenPos = new Vector2();
		boundingBox = new Rectangle();
		avrCenPos = new Vector2();
	}
	
	public void setPos(float x, float y){
		viewPos.set(x, y);
		for (int i = 0; i < pointList.size(); i++) {
			pointList.get(i).set(viewPos.x + (orinPointList.get(i).x - polyCordCenPos.x), 
					viewPos.y + (orinPointList.get(i).y - polyCordCenPos.y));
		}
		updateBoundingBox();
		setCenterPos();
	}
	
	public Rectangle getBoundingBox(){
		return boundingBox;
	}
	
	public int getPointCount(){
		return pointList.size();
	}
	
	public Vector2 getPoint(int index){
		return pointList.get(index);
	}
	
	public Vector2 getEdge(int index){
		return edgeList.get(index);
	}
	
	public int getEdgeCount(){
		return edgeList.size();
	}
	
	public void lockAddPoint(float vW, float vH){
		lockBoolean = true;
		polyCordW = vW;
		polyCordH = vH;
		polyCordCenPos.set((float)polyCordW / 2, (float)polyCordH / 2);
	}
	
	public Vector2 getAVRCenter(){
		return avrCenPos;
	}
	
	//edge`s vector is reverse clock wise
	public void addPoint(float px, float py){
		if(!lockBoolean)
			return;
		orinPointList.add(new Vector2(polyCordW * px , polyCordH * py));
	}
	
	public void unLockAddPoint(){
		lockBoolean = false;
		int pointCount = orinPointList.size();
		for(int i = 0; i < pointCount; i++){
			pointList.add(new Vector2(orinPointList.get(i)));
			edgeList.add(new Vector2());
		}
		updateEdgeList(pointCount);
		updateBoundingBox();
		setCenterPos();
	}
	
	private void setCenterPos(){
		float totalX = 0, totalY = 0;
		for (int i = 0; i < pointList.size(); i++) {
			totalX += pointList.get(i).x;
			totalY += pointList.get(i).y;
		}
		avrCenPos.set(totalX / (float)pointList.size(), totalY / (float)pointList.size());
	}
	
	//To find the values for (max_x, min_x, max_y, min_y), you can use the following simple algorithm:
	//Initialize (max_x=0, min_x=0, max_y=0, min_y=0). This assumes that the center of the polygon is at (0,0).
	//For each vertex in the polygon, test the (x,y) component against (max_x, min_x, max_y, min_y) and update appropriately.
	private void updateBoundingBox(){
		if(pointList.size() < 2)
			return;
		Vector2 pointChd = pointList.get(0);
		float minX = pointChd.x, maxX = pointChd.x, minY = pointChd.y, maxY = pointChd.y;
		for(int i = 1; i < pointList.size(); i++){
			pointChd = pointList.get(i);
			if(pointChd.x < minX)
				minX = pointChd.x;
			if(pointChd.x > maxX)
				maxX = pointChd.x;
			if(pointChd.y < minY)
				minY = pointChd.y;
			if(pointChd.y > maxY)
				maxY = pointChd.y;
		}
		boundingBox.setLowerLeft(minX, minY);
		boundingBox.setWidthHeight(maxX - minX, maxY - minY);
	}
	
	private void updateEdgeList(int pointCount){
		if(pointCount > 1){
			for(int i = 1; i < pointCount; i++){
				Vector2 rearVertex = pointList.get(i);
				Vector2 frontRearVertex = pointList.get(i-1);
				edgeList.get(i-1).set(rearVertex.x - frontRearVertex.x,
						rearVertex.y - frontRearVertex.y);
			}
			if(pointCount > 2)
				edgeList.get(edgeList.size()-1).set(pointList.get(0).x - pointList.get(pointList.size()-1).x,
						pointList.get(0).y - pointList.get(pointList.size()-1).y);
		}
		for(int i = 0; i < edgeList.size(); i++)
			edgeList.get(i).nor();
	}
	
	//if point list update : update edge list | bounding box
	public void setRot(float rad){
		float sinVal = FloatMath.sin(rad);
		float cosVal = FloatMath.cos(rad);
		for(int i = 0; i < pointList.size(); i++){
			pointList.get(i).set(orinPointList.get(i).x - polyCordCenPos.x, orinPointList.get(i).y - polyCordCenPos.y);
			pointList.get(i).set(pointList.get(i).x * cosVal + pointList.get(i).y * sinVal, 
					- pointList.get(i).x * sinVal + pointList.get(i).y * cosVal);
			pointList.get(i).add(viewPos.x, viewPos.y);
		}
		updateEdgeList(pointList.size());
		updateBoundingBox();
		setCenterPos();
	}
}
